﻿using System;
using System.Collections.Generic;
using LightPersist.Storage;
using LightPersist.Transactions;

namespace LightPersist
{

	class TransactionProcessingContext
	{
		readonly Dictionary<string, NotifyMapEntry> _mapTargetToAction = new Dictionary<string, NotifyMapEntry>();
		public readonly DagCheckingContext DagContext = new DagCheckingContext();
		public readonly LightPersistContext LightPersistContext;
		public readonly TransactionProcessor Processor;
		public readonly IStorage Storage;

		#region Properties

		public List<ListActionData> ActionsList { get; set; }

		public Dictionary<string, NotifyMapEntry> MapTargetToAction
		{
			get { return _mapTargetToAction; }
		}

		public ProcessFlags Flags { get; set; }

		public bool NeedUpdateStorage
		{
			get { return (Flags & ProcessFlags.UpdateStorage) != 0; }
		}

		public bool NeedCloseTransactions
		{
			get { return (Flags & ProcessFlags.CloseTransactions) != 0; }
		}

		public bool NeedUpdateComponents
		{
			get { return (Flags & ProcessFlags.UpdateUI) != 0; }
		}

		public bool NeedUpdateModel
		{
			get { return (Flags & ProcessFlags.UpdateModel) != 0; }
		}

		#endregion

		public TransactionProcessingContext(TransactionProcessor processor, ProcessFlags flags, LightPersistContext ctx)
		{
			Processor = processor;
			Storage = ctx.Storage;
			LightPersistContext = ctx;
			Flags = flags;
			ActionsList = new List<ListActionData>();
		}

		public void ScheduleNotifyPropertyValue(TheAction action, object oldValue, object newValue)
		{
			var target = action.TargetModel.ID + action.PropertyName;
			NotifyMapEntry entry;
			var map = MapTargetToAction;
			if (map.TryGetValue(target, out entry))
			{
				entry.LastAction = action;
				entry.LastValue = newValue;
			}
			else
			{
				map.Add(target, new NotifyMapEntry { InitialValue = oldValue, LastValue = newValue, LastAction = action });
			}
		}

		public void AddToNotifyActionList(TheAction action, ListActionData data)
		{
			ActionsList.Add(data);
		}

		public void Perform(Action<TransactionProcessingContext> updateModel, Action<TransactionProcessingContext> updateComponents, Action<TransactionProcessingContext> updateStorage)
		{
			if (NeedUpdateModel && updateModel != null)
			{
				updateModel(this);
			}

			if (NeedUpdateComponents && updateComponents != null)
			{
				updateComponents(this);
			}

			if (NeedUpdateStorage && updateStorage != null)
			{
				updateStorage(this);
			}
		}
	}

	#region NotifyMapEntry

	class NotifyMapEntry
	{
		public object InitialValue, LastValue;
		public TheAction LastAction;
	}

	#endregion
}